package admin

import (
	"context"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/internal/rpc/module/admin/adminLogic"
	"grpc.getaway.adminspro.padmins.com/internal/rpc/utils/database"
	"grpc.getaway.adminspro.padmins.com/pkg/businessCommonQuery"
	"grpc.getaway.adminspro.padmins.com/pkg/config/businessError"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
	pbAdmin "grpc.getaway.adminspro.padmins.com/pkg/proto/admin"
)

func (rpc *admin) AdminIndex(ctx context.Context, pb *pbAdmin.AdminIndexReq) (*pbAdmin.AdminIndexResp, error) {
	where, bindValue, limit, order, e := businessCommonQuery.BuildByBusinessCommonQuery(pb.BusinessCommonQuery)

	if e != nil {
		return nil, businessError.ErrorInfoToRpcError(e)
	}

	adminIds := []interface{}{}
	authRuleIds := []interface{}{}
	roleIds := []interface{}{}
	if pb.OperaterId != 0 {
		roleIds = adminLogic.GetChildrenRoleIds(ctx, pb.OperaterId, true)
		adminIds = adminLogic.GetChildrenAdminIdsByRoleIds(ctx, roleIds, pb.OperaterId, true)
		authRuleIds = adminLogic.GetRoleIdsByAdminId(ctx, pb.OperaterId)
	}

	if len(adminIds) > 0 {
		where += " and a.id in (?)"
		bindValue = append(bindValue, adminIds)
	}

	resp := &pbAdmin.AdminIndexResp{}
	Db := database.Db.GetDefaultDb(ctx)
	if pb.ShowTotal {
		total, dbErr := Db.Find(fmt.Sprintf("select count(distinct a.id) total from admin a "+
			"left join admin_role_access agc on agc.admin_id=a.id "+
			"where 1=1 %s", where), bindValue...)

		if dbErr != nil {
			return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
		}

		resp.Total = total["total"].(int64)
	}

	rows, dbErr := Db.Query(fmt.Sprintf("select a.* from admin a left join admin_role_access agc on agc.admin_id=a.id "+
		"where 1=1 %s group by a.id %s %s", where, order, limit), bindValue...)

	if dbErr != nil {
		return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
	}

	if len(rows) > 0 {
		adminIds := utils.ArrayColumn(rows, "id")
		roleRows, dbErr := Db.Query("select a.admin_id,g.* from admin_role_access a "+
			"join admin_role g on g.id=a.role_id "+
			"where admin_id in (?) and g.id in (?)", adminIds, roleIds)

		if dbErr != nil {
			return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
		}
		rolesMap := map[string][]map[string]interface{}{}
		for _, role := range roleRows {
			rolesMap[fmt.Sprintf("%v", role["admin_id"])] = append(rolesMap[fmt.Sprintf("%v", role["admin_id"])], role)
		}

		resp.Rows = make([]*pbAdmin.Admin, len(rows))
		list := adminLogic.List()
		for i, row := range rows {
			businessCommonQuery.ListFormat(list, row)
			row["role_id"] = ""
			row["role_text"] = ""
			row["disabled"] = 0
			if roles, ok := rolesMap[fmt.Sprintf("%v", row["id"])]; ok {
				ids := []string{}
				names := []string{}
				ids2 := []interface{}{}
				for _, role := range roles {
					ids = append(ids, fmt.Sprintf("%v", role["id"]))
					ids2 = append(ids2, role["id"])
					names = append(names, fmt.Sprintf("%v", role["name"]))
				}
				row["role_id"] = utils.Implode(",", ids)
				row["role_text"] = utils.Implode(",", names)
				if len(utils.ArrayIntersect(ids2, authRuleIds)) > 0 {
					row["disabled"] = 1
				}
			}
			resp.Rows[i] = &pbAdmin.Admin{
				Id:              row["id"].(int64),
				Email:           row["email"].(string),
				Username:        row["username"].(string),
				Nickname:        row["nickname"].(string),
				Password:        row["password"].(string),
				Salt:            row["salt"].(string),
				Avatar:          row["avatar"].(string),
				Loginfailure:    int32(row["loginfailure"].(int64)),
				Token:           row["token"].(string),
				TokenExpiryTime: row["token_expiry_time"].(string),
				Status:          int32(row["status"].(int64)),
				LoginTime:       row["login_time"].(string),
				CreateTime:      row["create_time"].(string),
				UpdateTime:      row["update_time"].(string),
				StatusText:      row["status_text"].(string),
				RoleId:          row["role_id"].(string),
				RoleText:        row["role_text"].(string),
				Disabled:        int32(row["disabled"].(int)),
			}
		}
	}

	return resp, nil
}
